home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / quicktime vr / vrspeech / vrspeech.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  16.8 KB  |  670 lines

  1. //////////
  2. //
  3. //    File:        VRSpeech.c
  4. //
  5. //    Contains:    Speech recognition support for QuickTime VR movies.
  6. //
  7. //    Written by:    Tim Monroe
  8. //
  9. //    Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  10. //
  11. //    Change History (most recent first):
  12. //
  13. //       <4>         06/19/98    rtm        minor clean-up for inclusion in QT3 SDK
  14. //       <3>         07/10/97    rtm        added ReleaseResource call to VRSpeech_ReadLanguageModelsFromResource
  15. //       <2>         03/07/97    rtm        added VRSpeech_ prefix to all routines
  16. //       <1>         12/05/96    rtm        ported earlier speech recognition support functions to VRShell
  17. //
  18. //////////
  19.  
  20. // TO DO:
  21. // + on a mousedown event in QTVR window, stop spinning immediately??
  22. // + implement node navigation
  23. // + presumably, spinning should be on a per-instance basis
  24.  
  25.  
  26. // header files
  27. #include "VRSpeech.h"
  28. #include "LMSpeech.h"        // refcons of language model elements
  29.  
  30. #include "MacFramework.h"
  31. #include "QTVRUtilities.h"
  32.  
  33. // system headers
  34. #include <Resources.h>
  35. #include <FixMath.h>
  36. #include <Speech.h>
  37. #include <stdlib.h>
  38.  
  39. extern Boolean gHasSpeechRec;
  40.  
  41. // declare global variables
  42. SRRecognitionSystem        gSystem;
  43. SRRecognizer            gRecognizer;
  44. SRLanguageModel            gVRLM;
  45. MyTMTask                 gTMTaskRec;
  46. TimerUPP                gTimerTaskUPP;
  47. Boolean                    gDoSpeechTask;        // is a speech-initiated periodical active?
  48.  
  49. // local function prototypes
  50. PASCAL_RTN void            VRSpeech_SpinTask (MyTMTaskPtr theTaskPtr);
  51. PASCAL_RTN void            VRSpeech_SpeechFeedbackRoutine (QTVRInstance theInstance, QTVRInterceptPtr theMsg, SInt32 refcon, Boolean *cancel);
  52.  
  53.  
  54. //////////
  55. //
  56. // VRSpeech_Init
  57. // Initialize speech recognition, if it's available.
  58. //
  59. //////////
  60.  
  61. void VRSpeech_Init (void)
  62. {
  63.     long            myResponse;
  64.     unsigned long    myParam;
  65.     OSErr            myErr = noErr;
  66.     
  67.     myErr = Gestalt(gestaltSpeechRecognitionVersion, &myResponse);
  68.     // version must be at least 1.5.0 to support SRM API used here
  69.     if (myErr == noErr)
  70.         if (myResponse >= 0x00000150)
  71.             gHasSpeechRec = true;
  72.         
  73.     if (!gHasSpeechRec)
  74.         return;
  75.         
  76.     // open a recognition system
  77.     if (myErr == noErr)
  78.         myErr = SROpenRecognitionSystem(&gSystem, kSRDefaultRecognitionSystemID);
  79.     
  80.     // set recognition system properties
  81.     // we want the user-selected feedback and listening modes
  82.     if (myErr == noErr) {
  83.         short myModes = kSRHasFeedbackHasListenModes;
  84.         
  85.         myErr = SRSetProperty(gSystem, kSRFeedbackAndListeningModes, &myModes, sizeof(myModes));
  86.     }
  87.  
  88.     // create a recognizer with default speech source
  89.     if (myErr == noErr)
  90.         myErr = SRNewRecognizer(gSystem, &gRecognizer, kSRDefaultSpeechSource);
  91.                         
  92.     // set recognizer properties
  93.     if (myErr == noErr) {
  94.         // we'd like *our* top-level LM to be the only one active;
  95.         Boolean myBlock = true;
  96.         
  97.         myErr = SRSetProperty(gRecognizer, kSRBlockBackground, &myBlock, sizeof(myBlock));
  98.         
  99.         // we want to receive speech-begun and recognition-done Apple events
  100.         myParam = kSRNotifyRecognitionBeginning | kSRNotifyRecognitionDone;
  101.         myErr = SRSetProperty(gRecognizer, kSRNotificationParam, &myParam, sizeof(myParam));
  102.     }
  103.  
  104.     // install Apple event handlers
  105.     if (myErr == noErr) {
  106.         myErr = AEInstallEventHandler(kAESpeechSuite, kAESpeechDetected, NewAEEventHandlerProc(VRSpeech_HandleSpeechBegunAppleEvent), 0, false);
  107.         myErr = AEInstallEventHandler(kAESpeechSuite, kAESpeechDone, NewAEEventHandlerProc(VRSpeech_HandleSpeechDoneAppleEvent), 0, false);
  108.     }
  109.             
  110.     // get our language models
  111.     if (myErr == noErr)
  112.         myErr = VRSpeech_ReadLanguageModelsFromResource();
  113.  
  114.     // install initial language model
  115.     if (myErr == noErr)
  116.         myErr = SRSetLanguageModel(gRecognizer, gVRLM);
  117.  
  118.     // have the recognizer start processing sound
  119.     if (myErr == noErr)
  120.         myErr = SRStartListening(gRecognizer);    
  121.     
  122.     // allocate our spinning task
  123.     gTimerTaskUPP = NewTimerProc(VRSpeech_SpinTask);
  124. }
  125.  
  126.  
  127. //////////
  128. //
  129. // VRSpeech_Stop
  130. // Shut down speech recognition.
  131. //
  132. //////////
  133.  
  134. void VRSpeech_Stop (void)
  135. {
  136.     // stop any spinning before we exit
  137.     if (VRSpeech_IsSpinning())
  138.         VRSpeech_StopSpinning();
  139.  
  140.     // release any existing language models
  141.     SRReleaseObject(gVRLM);
  142.     
  143.     // shut down speech recognition
  144.     SRStopListening(gRecognizer);            // stop processing incoming sound
  145.     SRReleaseObject(gRecognizer);            // balance SRNewRecognizer call
  146.     SRCloseRecognitionSystem(gSystem);        // balance SROpenRecognitionSystem call
  147. }
  148.  
  149.  
  150. //////////
  151. //
  152. // VRSpeech_HandleSpeechBegunAppleEvent
  153. // Handle speech-begun events; currently this does nothing interesting; 
  154. // in the future, we'll use it to adjust our language models according to context.
  155. //
  156. //////////
  157.  
  158. PASCAL_RTN OSErr VRSpeech_HandleSpeechBegunAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
  159. {
  160. #pragma unused(reply, refcon)
  161.  
  162.     long                myActualSize;
  163.     DescType            myActualType;
  164.     SRRecognizer        myRec;
  165.     OSErr                myErr = noErr, recErr = noErr;
  166.     
  167.     // get status and recognizer
  168.     myErr = AEGetParamPtr(theAEevt, keySRSpeechStatus, typeShortInteger, &myActualType, (Ptr)&recErr, sizeof(recErr), &myActualSize);
  169.     if ((myErr == noErr) && (recErr == noErr))
  170.         myErr = AEGetParamPtr(theAEevt, keySRRecognizer, typeSRRecognizer, &myActualType, (Ptr)&myRec, sizeof(myRec), &myActualSize);
  171.     
  172.     // better bail if I couldn't get status or recognizer!
  173.     if (myErr != noErr)
  174.         if (myRec == NULL)
  175.             return(myErr);
  176.             
  177.     // here is where we would adjust LMs according to context
  178.     
  179.     // now tell the recognizer to continue
  180.     myErr = SRContinueRecognition(myRec);
  181.     return(myErr);
  182. }
  183.  
  184.  
  185. //////////
  186. //
  187. // VRSpeech_HandleSpeechDoneAppleEvent
  188. // Handle recognition-done Apple event.
  189. //
  190. //////////
  191.  
  192. PASCAL_RTN OSErr VRSpeech_HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
  193. {
  194. #pragma unused(reply, refcon)
  195.  
  196.     long                    myActualSize;
  197.     DescType                myActualType;
  198.     SRRecognitionResult        myRecResult;    
  199.     SRLanguageModel            myResultLM;
  200.     Size                    myLen;
  201.     QTVRInstance            myInstance;
  202.     long                    myDir;            // the direction we're moving
  203.     long                    myAmt;            // the amount we're moving
  204.     long                    myCount;
  205.     OSErr                    myErr = noErr, recErr = noErr;
  206.     
  207.     // get recognition result status
  208.     myErr = AEGetParamPtr(theAEevt, keySRSpeechStatus, typeShortInteger, &myActualType, (Ptr)&recErr, sizeof(recErr), &myActualSize);
  209.  
  210.     // get recognition result
  211.     if ((myErr == noErr) && (recErr == noErr))
  212.         myErr = AEGetParamPtr(theAEevt, keySRSpeechResult, typeSRSpeechResult, &myActualType, (Ptr)&myRecResult, sizeof(myRecResult), &myActualSize);
  213.                     
  214.     // better bail if I couldn't get the recognition result!
  215.     if (myErr != noErr)
  216.         return(myErr);
  217.  
  218.     // get the current movie
  219.     myInstance = GetQTVRInstanceFromFrontWindow();
  220.     if (myInstance == NULL) 
  221.         return(invalidMovie);
  222.     
  223.     // extract the language model from the recognition result...
  224.     myLen = sizeof(myResultLM);
  225.     myErr = SRGetProperty(myRecResult, kSRLanguageModelFormat, &myResultLM, &myLen);
  226.         
  227.     if (myErr == noErr) {
  228.         long                    myRefCon;
  229.         SRLanguageObject        myItem1;
  230.         SRLanguageObject        myItem2;
  231.         SRPath                    myPath;
  232.         
  233.         // ...and then get its refcon, so we know which one it is
  234.         myLen = sizeof(myRefCon);
  235.         myErr = SRGetProperty(myResultLM, kSRRefCon, &myRefCon, &myLen);
  236.             
  237.         // at this point, the refcon better be kVRAllCmd; otherwise, bail
  238.         if (myRefCon != kVRAllCmd)
  239.             return(kSRModelMismatch);
  240.         
  241.         // get the one and only item in the top-level language model, a path
  242.         myErr = SRGetIndexedItem(myResultLM, &myPath, 0);
  243.         myLen = sizeof(myRefCon);
  244.         myErr = SRGetProperty(myPath, kSRRefCon, &myRefCon, &myLen);
  245.  
  246.         switch (myRefCon) {
  247.             case kMoveDirAndDeg:    // these two parse similarly
  248.             case kMoveDirAndRad:
  249.                     myErr = SRGetIndexedItem(myPath, &myItem1, 1);        // it's a one-item LM!
  250.                     myErr = SRGetIndexedItem(myItem1, &myItem2, 0);        // so get the enclosed item
  251.                     myLen = sizeof(myRefCon);
  252.                     myErr = SRGetProperty(myItem2, kSRRefCon, &myDir, &myLen);
  253.                     myErr = SRGetIndexedItem(myPath, &myItem1, 2);        // it's a one-item LM!
  254.                     myErr = SRGetIndexedItem(myItem1, &myItem2, 0);        // so get the enclosed item
  255.                     myLen = sizeof(myRefCon);
  256.                     myErr = SRGetProperty(myItem2, kSRRefCon, &myAmt, &myLen);
  257.                     if (myRefCon == kMoveDirAndDeg)
  258.                         VRSpeech_GoDirByDegrees(myInstance, myDir, myAmt);
  259.                     else
  260.                         VRSpeech_GoDirByRadians(myInstance, myDir, myAmt);
  261.                     break;
  262.                 break;
  263.             
  264.             case kMoveToNode:
  265.                 break;
  266.                 
  267.             case kZoomDir:
  268.                 myErr = SRCountItems(myPath, &myCount);
  269.                 myErr = SRGetIndexedItem(myPath, &myItem1, myCount - 1);    // it's a one-item LM!
  270.                 myErr = SRGetIndexedItem(myItem1, &myItem2, 0);                // so get the enclosed item
  271.                 myLen = sizeof(myRefCon);
  272.                 myErr = SRGetProperty(myItem2, kSRRefCon, &myDir, &myLen);
  273.                 VRSpeech_ZoomInOrOut(myInstance, myDir);
  274.                 break;
  275.                 
  276.             case kSpinStart:
  277.                 myErr = SRGetIndexedItem(myPath, &myItem1, 1);            // it's a one-item LM!
  278.                 myErr = SRGetIndexedItem(myItem1, &myItem2, 0);            // so get the enclosed item
  279.                 myLen = sizeof(myRefCon);
  280.                 myErr = SRGetProperty(myItem2, kSRRefCon, &myDir, &myLen);
  281.                 VRSpeech_StartSpinning(myInstance, myDir);
  282.                 break;
  283.                 
  284.             case kSpinStop:
  285.                 VRSpeech_StopSpinning();
  286.                 break;
  287.                 
  288.             default:
  289.                 break;
  290.         }            
  291.         
  292.         SRReleaseObject(myItem1);
  293.         SRReleaseObject(myItem2);
  294.         SRReleaseObject(myPath);
  295.     }
  296.                         
  297.     // release recognition result, since we are done with it
  298.     SRReleaseObject(myRecResult);
  299.     SRReleaseObject(myResultLM);
  300.  
  301.     return(myErr);
  302. }
  303.  
  304.  
  305. //////////
  306. //
  307. // VRSpeech_ReadLanguageModelsFromResource
  308. // Get our language model(s); here we read a pre-rolled model from a resource.
  309. //
  310. //////////
  311.  
  312. OSErr VRSpeech_ReadLanguageModelsFromResource (void)
  313. {
  314.     Handle            myResourceHandle = NULL;
  315.     OSErr            myErr = noErr;
  316.     
  317.     // open the language model resource from the resource fork
  318.     myResourceHandle = GetResource(kLMResourceType, kLMResourceID);
  319.     if (myResourceHandle == NULL) 
  320.         return(ResError());
  321.     
  322.     // convert language model resource to a language model
  323.     myErr = SRNewLanguageObjectFromHandle(gSystem, &gVRLM, myResourceHandle);
  324.     ReleaseResource(myResourceHandle);
  325.     return(myErr);
  326. }
  327.  
  328.  
  329. //////////
  330. //
  331. // VRSpeech_GoDirByDegrees
  332. // Move a given number of degrees in a given direction.
  333. // Return value: TRUE if a movement was made; FALSE if no movement was made.
  334. //
  335. //////////
  336.  
  337. Boolean VRSpeech_GoDirByDegrees (QTVRInstance theInstance, long theDir, long theAmt)
  338. {
  339.     float        myAngle;
  340.     Boolean        isMoved = false;
  341.     
  342.     QTVRSetAngularUnits(theInstance, kQTVRDegrees);
  343.     
  344.     // convert the constant to a number of degrees;
  345.     // sheesh, could there be an uglier way of doing this?
  346.     switch (theAmt) {
  347.         case kAng45:
  348.             theAmt = 45.0;
  349.             break;
  350.         case kAng90    :
  351.             theAmt = 90.0;
  352.             break;
  353.         case kAng135:
  354.             theAmt = 135.0;
  355.             break;
  356.         case kAng180:
  357.             theAmt = 180.0;
  358.             break;
  359.         case kAng225:
  360.             theAmt = 225.0;
  361.             break;
  362.         case kAng270:
  363.             theAmt = 270.0;
  364.             break;
  365.         case kAng315:
  366.             theAmt = 315.0;
  367.             break;
  368.         case kAng10:
  369.             theAmt = 10.0;
  370.             break;
  371.         case kAng36:
  372.             theAmt = 36.0;
  373.             break;
  374.         case kUndefinedDegrees:
  375.             theAmt = 5.0;
  376.             break;
  377.         default:
  378.             theAmt = 10.0;
  379.             break;
  380.     }
  381.     
  382.     switch (theDir) {
  383.         case kDirUp:
  384.             myAngle = QTVRGetTiltAngle(theInstance);
  385.             QTVRSetTiltAngle(theInstance, myAngle + theAmt);
  386.             break;
  387.             
  388.         case kDirDown:
  389.             myAngle = QTVRGetTiltAngle(theInstance);
  390.             QTVRSetTiltAngle(theInstance, myAngle - theAmt);
  391.             break;
  392.             
  393.         case kDirLeft:
  394.             myAngle = QTVRGetPanAngle(theInstance);
  395.             QTVRSetPanAngle(theInstance, myAngle + theAmt);
  396.             break;
  397.             
  398.         case kDirRight:
  399.             myAngle = QTVRGetPanAngle(theInstance);
  400.             QTVRSetPanAngle(theInstance, myAngle - theAmt);
  401.             break;
  402.             
  403.         default:
  404.             break;
  405.     }
  406.  
  407.     QTVRUpdate(theInstance, kQTVRStatic);
  408.     
  409.     // determine whether a movement actually occurred
  410.     switch (theDir) {
  411.         case kDirUp:
  412.         case kDirDown:
  413.             isMoved = (myAngle != QTVRGetTiltAngle(theInstance));
  414.             break;
  415.         case kDirLeft:
  416.         case kDirRight:
  417.             isMoved = (myAngle != QTVRGetPanAngle(theInstance));
  418.             break;
  419.         default:
  420.             break;
  421.     }
  422.     
  423.     return(isMoved);
  424. }
  425.  
  426.  
  427. //////////
  428. //
  429. // VRSpeech_GoDirByRadians
  430. // Move a given number of radians in a given direction.
  431. // Return value: TRUE if a movement was made; FALSE if no movement was made.
  432. //
  433. //////////
  434.  
  435. Boolean VRSpeech_GoDirByRadians (QTVRInstance theInstance, long theDir, long theAmt)
  436. {
  437.     // convert radians to degrees, then call VRSpeech_GoDirByDegrees
  438.     switch (theAmt) { 
  439.         case kRad1PiOver4:
  440.             theAmt = kAng45;
  441.             break;
  442.         case kRad2PiOver4:
  443.             theAmt = kAng90;
  444.             break;
  445.         case kRad3PiOver4:
  446.             theAmt = kAng135;
  447.             break;
  448.         case kRad4PiOver4:
  449.             theAmt = kAng180;
  450.             break;
  451.         case kRad5PiOver4:
  452.             theAmt = kAng225;
  453.             break;
  454.         case kRad6PiOver4:
  455.             theAmt = kAng270;
  456.             break;
  457.         case kRad7PiOver4:
  458.             theAmt = kAng315;
  459.             break;
  460.         default:
  461.             theAmt = kAng10;
  462.             break;
  463.     }
  464.     
  465.     return(VRSpeech_GoDirByDegrees(theInstance, theDir, theAmt));
  466. }
  467.  
  468.  
  469. //////////
  470. //
  471. // VRSpeech_ZoomInOrOut
  472. // Zoom in or out.
  473. //
  474. //////////
  475.  
  476. void VRSpeech_ZoomInOrOut (QTVRInstance theInstance, long theDir)
  477. {
  478.     float    myFloat;
  479.     
  480.     myFloat = QTVRGetFieldOfView(theInstance);
  481.     switch (theDir) {
  482.         case kDirIn:
  483.             myFloat = myFloat / 2.0; 
  484.             break;
  485.         case kDirOut:
  486.             myFloat = myFloat * 2.0; 
  487.             break;
  488.         default:
  489.             break;
  490.     }
  491.     
  492.     QTVRSetFieldOfView(theInstance, myFloat);    
  493.     QTVRUpdate(theInstance, kQTVRStatic);
  494. }
  495.  
  496.  
  497. //////////
  498. //
  499. // VRSpeech_SpinTask
  500. // Move in the desired direction, then re-prime the timer task.
  501. // (Here we just set an app global to alert code in event loop to do the move).
  502. //
  503. //////////
  504.  
  505. PASCAL_RTN void VRSpeech_SpinTask (MyTMTaskPtr theTaskPtr)
  506. {
  507.     gDoSpeechTask = true;
  508.     PrimeTime((QElemPtr)theTaskPtr, theTaskPtr->theSpinDelay);
  509. }
  510.  
  511.  
  512. //////////
  513. //
  514. // VRSpeech_DoEventLoopSpinCheck
  515. // See whether a spin task is active, and respond appropriately.
  516. //
  517. //////////
  518.  
  519. void VRSpeech_DoEventLoopSpinCheck (void)
  520. {
  521.     if (gDoSpeechTask) {
  522.         if (!VRSpeech_GoDirByDegrees(gTMTaskRec.theInstance, gTMTaskRec.theSpinDir, gTMTaskRec.theSpinAmt))
  523.             VRSpeech_StopSpinning();
  524.         
  525.         gDoSpeechTask = false;
  526.     }
  527. }
  528.  
  529.  
  530. //////////
  531. //
  532. // VRSpeech_IsSpinning
  533. // Is the spinning task installed?
  534. //
  535. //////////
  536.  
  537. Boolean VRSpeech_IsSpinning (void)
  538. {
  539.     return(gTMTaskRec.theTMTask.qType && kTMTaskActive);
  540. }
  541.  
  542.  
  543. //////////
  544. //
  545. // VRSpeech_StartSpinning
  546. // Start spinning in a given direction.
  547. //
  548. //////////
  549.  
  550. void VRSpeech_StartSpinning (QTVRInstance theInstance, long theDir)
  551. {
  552.     // first we should check that our task isn't already installed;
  553.     // if it is, remove it (and then continue to install new task)
  554.     if (VRSpeech_IsSpinning())
  555.         VRSpeech_StopSpinning();
  556.         
  557.     // install a Time Manager task that periodically moves a small amount (5 degrees)
  558.     gTMTaskRec.theTMTask.tmAddr = gTimerTaskUPP;
  559.     gTMTaskRec.theTMTask.tmWakeUp = 0;
  560.     gTMTaskRec.theTMTask.tmReserved = 0;
  561.     gTMTaskRec.theInstance = theInstance;
  562.     gTMTaskRec.theSpinDir = theDir;
  563.     gTMTaskRec.theSpinAmt = kUndefinedDegrees;
  564.     gTMTaskRec.theSpinDelay = kSpinMillisecsDelay;
  565.  
  566.     InsXTime((QElemPtr) &gTMTaskRec);
  567.     PrimeTime((QElemPtr) &gTMTaskRec, kSpinMillisecsDelay);
  568. }
  569.  
  570.  
  571. //////////
  572. //
  573. // VRSpeech_StopSpinning
  574. // Stop spinning: remove the Time Manager task.
  575. //
  576. //////////
  577.  
  578. void VRSpeech_StopSpinning (void)
  579. {
  580.     RmvTime((QElemPtr) &gTMTaskRec);
  581. }
  582.  
  583.  
  584. //////////
  585. //
  586. // VRSpeech_InstallSpeechFeedbackRoutine
  587. // Set up QTVR intercept routines to do some speech.
  588. //
  589. //////////
  590.  
  591. void VRSpeech_InstallSpeechFeedbackRoutine (QTVRInstance theInstance)
  592. {
  593.     QTVRInterceptUPP     myInterceptProc;
  594.     
  595.     myInterceptProc = NewQTVRInterceptProc(VRSpeech_SpeechFeedbackRoutine);    
  596.     
  597.     // We'll just use the same intercept proc for each intercepted procedure.
  598.     QTVRInstallInterceptProc(theInstance, kQTVRSetPanAngleSelector, myInterceptProc, 0, 0);
  599.     QTVRInstallInterceptProc(theInstance, kQTVRSetTiltAngleSelector, myInterceptProc, 0, 0);
  600.     QTVRInstallInterceptProc(theInstance, kQTVRSetFieldOfViewSelector, myInterceptProc, 0, 0);
  601.     QTVRInstallInterceptProc(theInstance, kQTVRTriggerHotSpotSelector, myInterceptProc, 0, 0);
  602. }
  603.  
  604.  
  605. //////////
  606. //
  607. // VRSpeech_SpeechFeedbackRoutine
  608. //
  609. //////////
  610.  
  611. PASCAL_RTN void VRSpeech_SpeechFeedbackRoutine (QTVRInstance theInstance, QTVRInterceptPtr theMsg, SInt32 refCon, Boolean *cancel)
  612. {
  613. #pragma unused(refCon)
  614.  
  615.     Str255    myCaption;
  616.     Boolean myCancelInterceptedProc = false;            // true == do NOT call thru; false == call thru
  617.     float    myAngle, *myAnglePtr;
  618.     
  619.     switch (theMsg->selector) {
  620.         case kQTVRSetTiltAngleSelector:    
  621.         case kQTVRSetPanAngleSelector:
  622.         case kQTVRSetFieldOfViewSelector:
  623.             myAnglePtr = (float *)theMsg->parameter[0];
  624.             myAngle = *myAnglePtr;                        //this is always in radians!
  625.             myAngle = VRRadiansToDegrees(myAngle);
  626.             NumToString(Fix2Long(FloatToFixed(myAngle)), myCaption);            
  627.             QTVRCallInterceptedProc(theInstance, theMsg);
  628.             SpeakString(myCaption);
  629.             myCancelInterceptedProc = true;
  630.             break;
  631.             
  632.         case kQTVRTriggerHotSpotSelector:                // get the hot spot ID and speak it    
  633.             NumToString((long)theMsg->parameter[0], myCaption);            
  634.             SRSpeakAndDrawText(gRecognizer, &myCaption[1], myCaption[0]);
  635.             break;
  636.             
  637.         default:
  638.             break;
  639.     }
  640.     
  641.     *cancel = myCancelInterceptedProc;
  642. }
  643.  
  644.  
  645. //////////
  646. //
  647. // VRSpeech_SpeakNameOfNode
  648. // A sample node-entering procedure; we just welcome the user to the new node.
  649. //
  650. //////////
  651.  
  652. PASCAL_RTN OSErr VRSpeech_SpeakNameOfNode (QTVRInstance theInstance, long nodeID, SInt32 refCon)
  653. {
  654. #pragma unused(refCon)
  655.  
  656.     char         *myString;
  657.     
  658.     myString = QTVRUtils_GetNodeName(theInstance, nodeID);
  659.     if (myString) {
  660.         SpeakString("\p[[emph +]]Welcome [[emph -]] two");
  661.         while (SpeechBusy())
  662.             ;
  663.         SpeakString(c2pstr(myString));
  664.     }
  665.     
  666.     free(myString);
  667.     return(noErr);
  668. }
  669.  
  670.